\section{NAME\label{NAME}\index{NAME}}


Tutorial - Uso de Bench::Test con un ejemlo del calculo de Pi

\section{DESCRIPCION DEL PROBLEMA\label{DESCRIPCION_DEL_PROBLEMA}\index{DESCRIPCION DEL PROBLEMA}}
El calculo del numero $\pi$ es un problema con muchas posibles
soluciones y que ha sido ampliamente abordado por numerosas
técnicas de programación y de metodos numericos. Supongamos
que tenemos un fragmento de codigo en C como el que sigue:

\begin{verbatim}
  w = 1.0 / N;
  pi = 0.0;
  for (i = 0; i < N; i++) {
    local = (i + 0.5)*w;
    pi = pi + 4.0/(1.0 + local*local);
  }
\end{verbatim}


Un potencial usuario podria querer introducir mejoras
en este codigo o comparar ejecuciones de este mismo
programa en distintas maquinas.



El calculo del numero Pi se hace mediante la suma de una
una serie con N intervalos. Los parametros a considerar
en la ejecucion del programa son este numero de intervalos N,
el tiempo de ejecucion y el valor de Pi calculado.

\section{INSTRUMENTACION DEL PROGRAMA\label{INSTRUMENTACION_DEL_PROGRAMA}\index{INSTRUMENTACION DEL PROGRAMA}}


Para que el modulo Bench::Test pueda realizar su labor
correctamente el usuario del programa debe instrumentarlo
de forma que todos los parametros que le interesen han
de ser devueltos por el programa. Para ello puede volcar
la salida por la salida estandar o enviarlos a un fichero.



El objeto Bench::Test realiza las ejecuciones y
obtiene la salida o la lee desde un fichero para
a continuacion aplicar expresiones regulares que permitan
filtrar la informacion deseada. Por ello, a la hora
de instrumentar el programa debemos mostrar los
datos de forma que puedan ser facilmente reconocidos
mediante una sencilla expresion regular.



En este caso, supongamos que se instrumenta el programa
enviando los resultados a la salida estandar. El codigo
quedaria como sigue:

\begin{verbatim}
   ... Variable declaration
\end{verbatim}
\begin{verbatim}
   /* Save the start of interval */
   gettimeofday(&t1, NULL);
\end{verbatim}
\begin{verbatim}
   /* Calculate matrix product */
   for (i = 0; i < dim1; i++) {
      for (j = 0; j < dim3; j++) {
         C[i][j] = 0;
         for (k = 0; k < dim2; k++)
            C[i][j] += A[i][k] * B[k][j];
      }
   }
\end{verbatim}
\begin{verbatim}
   /* Save the end of interval */
   gettimeofday(&t2, NULL);
\end{verbatim}
\begin{verbatim}
   /* Calculate process duration */
   start = (double)(t1.tv_sec * 1.0e6) + (double)t1.tv_usec;
   end   = (double)(t2.tv_sec * 1.0e6) + (double)t2.tv_usec;
   diff  = (end - start) / 1.0e6;
\end{verbatim}
\begin{verbatim}
   /* Show process time */
   printf("Time: %f\n", diff);
   printf("Number of intervals: %d\n", N);
   printf("Calculated Pi: %1.20f\n", pi/N);
\end{verbatim}
\section{PARAMETROS DE CONFIGURACION\label{PARAMETROS_DE_CONFIGURACION}\index{PARAMETROS DE CONFIGURACION}}


Una vez instrumentado el programa cliente se ha de
definir los parametros que guien las ejecuciones. Para ello
existen dos posibilidades:

\begin{itemize}

\item 

Escribir un script perl que cree un objeto de la clase
Bench::Test con los parametros adecuados (ver documentacion
de Bench::Test).


\item 

Utilizar el script \textbf{maketest} proporcionado junto
con el modulo Bench::Test y definir los parametros
mediante un fichero de configuracion que, por defecto,
se llamara \textbf{maketest.conf} (ver documentacion del
script \textbf{maketest}.

\end{itemize}


La forma mas sencilla para un usuario sin conocimientos
de Perl es escribir el fichero de configuracion.



A continuacion empezamos a escribir, paso a paso, el
fichero de configuracion.

\section{EXPRESIONES REGULARES\label{EXPRESIONES_REGULARES}\index{EXPRESIONES REGULARES}}


La primera accion que realiza el objeto Bench::Test
despues de cada ejecucion es aplicar las expresiones
regulares sobre la salida generada por el programa
del usuario.



Estas expresiones definen los parametros de estudio
en los que el usuario esta interesado.



Para definirlas, se utiliza el array \textbf{@TABLE} y se
debe tener en cuenta el formato de salida del programa.



Una ejecucion de nuestro programa tendria la forma
siguiente:

\begin{verbatim}
   ~/Bench-Test/examples/pi$ ./pi 50000000
   Time: 0.644815
   Number of intervals: 50000000
   Calculated Pi: 3.14159265358952710656
\end{verbatim}


El array \textbf{@TABLE} podria tener la siguiente forma:

\begin{verbatim}
   @TABLE = (
      TIME => {  REGEXP => 'Time:\s+(.*?)\n' },
      NOI  => {  REGEXP => 'Number of intervals: (.*?)\n' },
      PI   => {  REGEXP => 'Calculated Pi: (.*?)\n' },
   );
\end{verbatim}


El array \textbf{@TABLE} esta formado por parejas clave-valor cuya
clave indica el nombre que el usuario desea dar al campo 
objeto de estudio y cuyo valor es un puntero a un hash cuyas
claves pueden ser dos:

\begin{description}

\item[{\textbf{CODE} (Opcional)}] \mbox{}

Contiene un puntero a una subrutina que es llamada justo despues
de que la salida case con la expresion regular definida en \textbf{REGEXP}.
Recibe como parametros la salida intacta del programa. Y en las
variables especiales \$1, \$2, etc. el contenido dentro de los
parentesis especificados en la expresion regular



Si no se especifica, la expresion regular debe tener una y solo
una parentizacion en el lugar exacto donde se encuentra el campo
objeto de estudio en cuestion.


\item[{\textbf{REGEXP}}] \mbox{}

Contiene la expresion regular que permite filtrar la salida.
Debe estar parentizada en los lugares en donde se encuentren
los campos objeto de estudio.

\end{description}
\section{PARAMETROS DE EJECUCION\label{PARAMETROS_DE_EJECUCION}\index{PARAMETROS DE EJECUCION}}


Una vez definidas las expresiones regulares que filtraran
la salida del programa, es hora de indicar los parametros
de ejecucion



Para ello se define el array \textbf{@TESTS} y en este caso podria
tener una forma como esta:

\begin{verbatim}
   @TESTS = (
      pi100000 =>    '100000',
      pi200000 =>    '200000',
      pi500000 =>    '500000',
      pi1000000 =>   '1000000',
      pi100000000 => '100000000',
      pi200000000 => '200000000',
      pi500000000 => '500000000',
   );
\end{verbatim}


Esta definicion generaria siete ejecuciones de la forma:

\begin{verbatim}
   <ejecutable>  100000
   <ejecutable>  200000
   <ejecutable>  500000
   <ejecutable>  1000000
   <ejecutable>  100000000
   <ejecutable>  200000000
   <ejecutable>  500000000
\end{verbatim}


Observese ademas que el array \textbf{@TESTS} esta formado
por pares clave-valor. El valor indica el nombre
del test correspondiente. El nombre de este test estara
disponible al usuario como un "campo" llamado \textbf{FILE}
como si hubiera sido definido en el array \textbf{@TABLE}.

\section{ENTORNOS DE EJECUCION\label{ENTORNOS_DE_EJECUCION}\index{ENTORNOS DE EJECUCION}}


Todavia no se han definido en el fichero de configuracion
los parametros relacionados con el ejecutable y el entorno
de ejecucion. Para ello se utiliza hash \textbf{\%EXPERIMENTS}.



El hash \textbf{\%EXPERIMENTS} esta formado por pares clave-valor
cuyas claves son el nombre que el usuario quiere dar a
sus entornos de ejecucion (por ejemplo, nombre de la maquina
donde se esta ejecutando), y cuyo valor es una referencia
a un objeto de la clase Bench::Test::Base, Bench::Test::Local
o Bench::Test::Remote (Ver documentacion).



Para este ejemplo podriamos definir un hash \textbf{\%EXPERIMENTS} de
la siguiente forma:

\begin{verbatim}
   %EXPERIMENTS = (
      'BASE'     => Bench::Test::Base->new (
                       WORKDIR   => './base_FEB'
                 ),
      'LOCAL'    => Bench::Test::Local->new  (
                       WORKDIR   => '.',
                       EXECUTABLE => './pi',
                    ),
      'ORION'    => Bench::Test::Remote->new (
                       HOST       => 'user@host',
                       WORKDIR    => '/home/user/mm',
                       EXECUTABLE => 'pi',
                    ),
   );
\end{verbatim}


Esta definicion contiene los tres posibles objetos: \textbf{Bench::Test::Local},
\textbf{Bench::Test::Local} y \textbf{Bench::Test::Remote}. La funcion de estos objetos
es definir los parametros de ejecucion en maquina local, remota o acceder
a resultados de ejecuciones anteriores (Bench::Test::Base).



Veamoslos por partes:

\section{Objeto \texttt{Bench::Test::Base}\label{Objeto_Bench::Test::Base}\index{Objeto Bench::Test::Base}}


El objeto Bench::Test::Base recibe com parametro en el constructor el
nombre del directorio en donde se encuentran almacenados los archivos
con las salidas de las ejecuciones anteriores que queremos comparar.



El nombre del archivo a leer consiste en nombre del \textbf{test} con la
extension \textbf{.base} al final. El nombre del test se ha definido
anteriormente como clave de los pares almacenados en el array \textbf{@TEST}.

\section{Objeto \texttt{Bench::Test::Local}\label{Objeto_Bench::Test::Local}\index{Objeto Bench::Test::Local}}


El objeto Bench::Test::Local se encarga de las ejecuciones en la 
maquina local. Su constructor recibe como parametros el directorio
de trabajo donde se encuentra el ejecutable y el nombre del ejecutable.

\section{Objeto \texttt{Bench::Test::Remote}\label{Objeto_Bench::Test::Remote}\index{Objeto Bench::Test::Remote}}


El objeto Bench::Test::Remote permite las ejecuciones en maquinas
remotas. Su constructor recibe como parametros el nombre del host
(y usuario, si hiciera falta) donde se van a lanzar las ejecuciones.
Tambien recibe el directorio de trabajo y el ejecutable en la
maquina remota.



Si el directorio de trabajo y el ejecutable no se encontraran en
la maquina remota, pueden definirse dos parametros (PREAMBLE y
POSTAMBLE) que permiten al usuario subir archivos y ejecutar
comandos en dicha maquina. Se trata de dos punteros a subrutina
que reciben como parametro una referencia al objeto
GRID::Machine con el que se ha establecido la conexion.



El modulo GRID::Machine permite subir archivos y ejecutar comandos
en la maquina remota con la que ha establecido conexion a traves
de SSH. Vease la documentacion de GRID::Machine para conocer
estas y muchas otras funcionalidades.

\section{Array \textbf{@VISUAL}\label{Array_VISUAL}\index{Array @VISUAL}}


Es posible que en algun momento queramos ver u ocultar alguno
de los campos que hemos especificado en el array \textbf{@TABLE}. Para
ello hacemos uso del array \textbf{@VISUAL}.



El array \textbf{@VISUAL} contiene una lista con los nombres de los
campos que queremos que aparezcan en la siguiente tanda de
ejecuciones. Por ejemplo:

\begin{verbatim}
   @VISUAL = qw(TEST FILE NOI TIME PI);
\end{verbatim}


En este caso estariamos indicando que queremos que se muestren
el numero de intervalo, el tiempo de ejecucion y el valor de Pi
obtenido con el programa. \textbf{TEST} y \textbf{FILE} que contienen el nombre
del test y el resultado (Ok o Fail).

\section{Array \textbf{@UNIQUE}\label{Array_UNIQUE}\index{Array @UNIQUE}}


Muchas veces ocurre que algunos campos son invariables dependiendo
del lugar donde se realicen las ejecuciones. En nuestro caso,
el numero de intervalos y el valor de Pi son los mismos en la
maquina local que en la maquina remota. Para evitar que el
modulo Bench::Test muestre estos valores para ambas maquinas
se especifican dichos campos en el array \textbf{@UNIQUE}:

\begin{verbatim}
   @UNIQUE = qw(NOI PI);
\end{verbatim}
\section{Array \textbf{@SELECTED}\label{Array_SELECTED}\index{Array @SELECTED}}


Al igual que con los campos y el array \textbf{@VISUAL}, tambien se
podria querer evitar que se realicen ejecuciones en ciertas. En
el array \textbf{@SELECTED} se indican los nombres de los "EXPERIMENTS"
que se desean realizar. Por ejemplo:

\begin{verbatim}
   @SELECTED = qw(BASE LOCAL ORION);
\end{verbatim}
\section{Array \textbf{@OUTPUTFORMAT}\label{Array_OUTPUTFORMAT}\index{Array @OUTPUTFORMAT}}


Por ultimo, solo queda definir el formato de salida con el 
array \textbf{@OUTPUTFORMAT}. Veamos un ejemplo:

\begin{verbatim}
   @OUTPUTFORMAT = (
      'text'  => '',
      'html'   => 'output.html',
   );
\end{verbatim}


Se trata de un hash cuyas claves indican el formato en el
que se quiere la salida y cuyo valor especifica el fichero
a donde se enviara la salida con ese formato. Si se deja
el valor en blanco la salida es enviada a salida estandar.



Los formatos disponibles son \textbf{text} (texto plano), \textbf{xml},
\textbf{html} y \textbf{LaTeX}. Ademas es posible que el usuario provea
un nuevo formato mediante la clave \textbf{file:fichero.tt} donde
\textbf{fichero.tt} es el nombre del fichero donde el usuario
ha escrito su plantilla con Template Toolkit (Ver
documentacion de Template Toolkit).



Para poder formatear la salida se debe esperar hasta que
se realice la ultima ejecucion. Sin embargo, y por defecto,
se muestra por pantalla linea a linea los resultados de
cada ejecucion formateados con simples tabuladores.

\section{FICHERO DE CONFIGURACION\label{FICHERO_DE_CONFIGURACION}\index{FICHERO DE CONFIGURACION}}


El fichero de configuracion quedaria como sigue:

\begin{verbatim}
   @TABLE = (
      TIME => {  REGEXP => 'Time:\s+(.*?)\n' },
      NOI  => {  REGEXP => 'Number of intervals: (.*?)\n' },
      PI   => {  REGEXP => 'Calculated Pi: (.*?)\n' },
   );
\end{verbatim}
\begin{verbatim}
   @TESTS = (
      pi100000 =>    '100000',
      pi200000 =>    '200000',
      pi500000 =>    '500000',
      pi1000000 =>   '1000000',
      pi100000000 => '100000000',
      pi200000000 => '200000000',
      pi500000000 => '500000000',
   );
\end{verbatim}
\begin{verbatim}
   %EXPERIMENTS = (
      'BASE'     => Bench::Test::Base->new (
                       WORKDIR   => './base_FEB'
                 ),
      'LOCAL'    => Bench::Test::Local->new  (
                       WORKDIR   => '.',
                       EXECUTABLE => './pi',
                    ),
      'ORION'    => Bench::Test::Remote->new (
                       HOST       => 'user@host',
                       WORKDIR    => '/home/user/pi',
                       EXECUTABLE => 'pi',
                    ),
   );
\end{verbatim}
\begin{verbatim}
   @VISUAL   = qw(TEST FILE NOI TIME PI);
   @UNIQUE   = qw(NOI PI);
   @SELECTED = qw(BASE LOCAL ORION);
\end{verbatim}
\begin{verbatim}
   @OUTPUTFORMAT = (
      'text'  => '',
      'html'   => 'output.html',
   );
\end{verbatim}
\section{RESULTADO\label{RESULTADO}\index{RESULTADO}}


Una ejecucion del script \textbf{maketest} con el fichero de configuracion
anteriormente descrito daria como resultado algo asi:

\begin{tiny}

\begin{verbatim}
   ~/projects/Bench-Test/examples/pi$ maketest 
   TEST    FILE    NOI     TIME(BASE_feb)  TIME(LOCAL)     TIME(ORION)     PI(BASE_feb)    PI(LOCAL)       PI(ORION)
   OK      pi100000        100000  0.001108        0.001093        0.001576        3.14159265359816020080  3.14159265359816020080       3.14159265359816020080
   OK      pi200000        200000  0.002209        0.002358        0.002949        3.14159265359189321387  3.14159265359189321387       3.14159265359189321387
   OK      pi500000        500000  0.005477        0.005475        0.007240        3.14159265359010175800  3.14159265359010175800       3.14159265359010175800
   OK      pi1000000       1000000 0.010948        0.011241        0.014544        3.14159265358976380611  3.14159265358976380611       3.14159265358976380611
   OK      pi100000000     100000000       1.110820        1.143022        1.450729        3.14159265359023454067  3.14159265359023454067       3.14159265359023454067
   OK      pi200000000     200000000       2.276124        2.301354        2.901209        3.14159265359011463659  3.14159265359011463659       3.14159265359011463659
   OK      pi500000000     500000000       6.549226        5.680707        7.260515        3.14159265359030781539  3.14159265359030781539       3.14159265359030781539
   TEST  FILE         NOI        TIME(BASE_feb)  TIME(LOCAL)  TIME(ORION)  PI(BASE_feb)            PI(LOCAL)               PI(ORION)               
   OK    pi100000     100000     0.001108        0.001093     0.001576     3.14159265359816020080  3.14159265359816020080  3.14159265359816020080  
   OK    pi200000     200000     0.002209        0.002358     0.002949     3.14159265359189321387  3.14159265359189321387  3.14159265359189321387  
   OK    pi500000     500000     0.005477        0.005475     0.007240     3.14159265359010175800  3.14159265359010175800  3.14159265359010175800  
   OK    pi1000000    1000000    0.010948        0.011241     0.014544     3.14159265358976380611  3.14159265358976380611  3.14159265358976380611  
   OK    pi100000000  100000000  1.110820        1.143022     1.450729     3.14159265359023454067  3.14159265359023454067  3.14159265359023454067  
   OK    pi200000000  200000000  2.276124        2.301354     2.901209     3.14159265359011463659  3.14159265359011463659  3.14159265359011463659  
   OK    pi500000000  500000000  6.549226        5.680707     7.260515     3.14159265359030781539  3.14159265359030781539  3.14159265359030781539
\end{verbatim}
\end{tiny}



La primera tabla es la que se ha ido generando ejecucion a ejecucion
mientras que la segunda se muestra al final formateandola correctamente.



Ademas, como se especifico en el array \textbf{@OUTPUTFORMAT} se crea un archivo
\textbf{output.html} similar a este:

\begin{verbatim}
   <table>
      <tr>
         <td>TEST</td><td>FILE</td><td>NOI</td><td>TIME(BASE_feb)</td><td>TIME(LOCAL)</td><td>TIME(ORION)</td><td>PI(BASE_feb)</td><td>PI(LOCAL)</td><td>PI(ORION)</td>
      </tr>
      <tr>
         <td>OK</td><td>pi100000</td><td>100000</td><td>0.001108</td><td>0.001093</td><td>0.001576</td><td>3.14159265359816020080</td><td>3.14159265359816020080</td><td>3.14159265359816020080</td>
      </tr>
      <tr>
         <td>OK</td><td>pi200000</td><td>200000</td><td>0.002209</td><td>0.002358</td><td>0.002949</td><td>3.14159265359189321387</td><td>3.14159265359189321387</td><td>3.14159265359189321387</td>
      </tr>
      <tr>
         <td>OK</td><td>pi500000</td><td>500000</td><td>0.005477</td><td>0.005475</td><td>0.007240</td><td>3.14159265359010175800</td><td>3.14159265359010175800</td><td>3.14159265359010175800</td>
      </tr>
      <tr>
         <td>OK</td><td>pi1000000</td><td>1000000</td><td>0.010948</td><td>0.011241</td><td>0.014544</td><td>3.14159265358976380611</td><td>3.14159265358976380611</td><td>3.14159265358976380611</td>
      </tr>
      <tr>
         <td>OK</td><td>pi100000000</td><td>100000000</td><td>1.110820</td><td>1.143022</td><td>1.450729</td><td>3.14159265359023454067</td><td>3.14159265359023454067</td><td>3.14159265359023454067</td>
      </tr>
      <tr>
         <td>OK</td><td>pi200000000</td><td>200000000</td><td>2.276124</td><td>2.301354</td><td>2.901209</td><td>3.14159265359011463659</td><td>3.14159265359011463659</td><td>3.14159265359011463659</td>
      </tr>
      <tr>
         <td>OK</td><td>pi500000000</td><td>500000000</td><td>6.549226</td><td>5.680707</td><td>7.260515</td><td>3.14159265359030781539</td><td>3.14159265359030781539</td><td>3.14159265359030781539</td>
      </tr>
   </table>
\end{verbatim}
\section{AUTHOR\label{AUTHOR}\index{AUTHOR}}


Casiano Rodriguez-Leon
Juan Antonio Gomez Cabo



$<$casiano@ull.es$>$
$<$gomezcabo@yahoo.es$>$

\section{COPYRIGHT AND LICENSE\label{COPYRIGHT_AND_LICENSE}\index{COPYRIGHT AND LICENSE}}


Copyright (C) 2006 by Casiano Rodriguez Leon, Juan Antonio Gomez Cabo



This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.4 or,
at your option, any later version of Perl 5 you may have available.

